//CS 564:: PROJECT STAGE 5 - RDBS Catalog
//
// Caela Northey (caela) 905 653 2238
// Colin Laska   (laska) 906 150 7258

#include "catalog.h"
#include "query.h"

// forward declaration
const Status ScanSelect(const string & result, 
			const int projCnt, 
			const AttrDesc projNames[],
			const AttrDesc *attrDesc, 
			const Operator op, 
			const char *filter,
			const int reclen);

// A selection is implemented using a filtered HeapFileScan. The 
// result of the selection is stored in the result relation called result
// (a  heapfile with this name will be created by the parser before
// QU_Select() is called).  The project list is defined by the parameters
// projCnt and projNames.  Projection should be done on the fly as each
// result tuple is being appended to the result table.  
//  
// NOTEs:-If attr is NULL, do an unconditional scan of the input table.
//       -The search value is always supplied as the character string
//        attrValue.  You should convert it to the proper type based on
//        the type of attr.
//       -Bits of this solution were taken from join.C, which was not
//        written by us.
const Status QU_Select(const string & result, 
		       const int projCnt, 
		       const attrInfo projNames[],
		       const attrInfo *attr, 
		       const Operator op, 
		       const char *attrValue)
{
   // Qu_Select sets up things and then calls ScanSelect to do the actual work
    cout << "Doing QU_Select " << endl;

  //retreive attr info from AttrCat
  AttrDesc ad;
  Status status;

  // go through the projection list and look up each in the 
  // attr cat to get an AttrDesc structure (for offset, length, etc)
  AttrDesc attrDescArray[projCnt];
  for (int i = 0; i < projCnt; i++)
  {
    Status status = attrCat->getInfo(projNames[i].relName, projNames[i].attrName,
                                     attrDescArray[i]);
    if (status != OK) {
        return status;
    }
  }//end for

  // get output record length from attrdesc structures
  int reclen = 0;
  for (int i = 0; i < projCnt; i++)
  {
      reclen += attrDescArray[i].attrLen;
  }

  if(attr != NULL){

    status = attrCat->getInfo(attr->relName, attr->attrName, ad);
    if (status != OK){
      return status; 
    }

    status = ScanSelect(result, projCnt, attrDescArray, &ad, op,
                        attrValue, reclen);
    if (status != OK){
      return status;
    }

  }else{ //unconditional scan => filter = NULL

    strcpy(ad.relName, projNames[0].relName);  //need relName, others ignored
    status = ScanSelect(result, projCnt, attrDescArray, &ad, op,
                        NULL, reclen);
    if (status != OK){
      return status;
    }

  }//end if attr NULL

  return status; //should be OK by here
}

#include "stdio.h"
#include "stdlib.h"
const Status ScanSelect(const string & result, 
			const int projCnt, 
			const AttrDesc projNames[],
			const AttrDesc *attrDesc, 
			const Operator op, 
			const char *filter,
			const int reclen)
{
    cout << "Doing HeapFileScan Selection using ScanSelect()" << endl;
 
  Status status;
  HeapFileScan *hfs;
  InsertFileScan *ifs;
  Record rec;
  RID rid;

  hfs = new HeapFileScan(attrDesc->relName, status);
  if(status != OK){
    return status;
  }

  Datatype dt;
  switch (attrDesc->attrType) {
    case 0: dt = STRING; break;
    case 1: dt = INTEGER; break;
    case 2: dt = FLOAT; break;
  }

  //Recall: startScan(const int offset, const int length, const Datatype
  //        type, const char* filter, const Operator op);
  status = hfs->startScan(attrDesc->attrOffset,attrDesc->attrLen,
                          dt, filter, op);
  if(status != OK){
    return status;
  }

  // find all matches (terminates when scanNext reaches EOF)
  while (1){
    
    // 1. find match

    status = hfs->scanNext(rid);  //puts match in curRec
    if(status == FILEEOF){
      status = OK;
      break;
    }else if (status != OK){
      return status;
    }

    status = hfs->getRecord(rec); //gets curRec
    if(status != OK){
      return status;
    }

    //2. put requested projections of match into result file
 
    // create data of result record
    char outputData[reclen];
    int offset = 0;
    for (int i = 0; i < projCnt; i++){
      memcpy(outputData+offset, rec.data+projNames[i].attrOffset,
             projNames[i].attrLen);
      offset += projNames[i].attrLen;
    }
    Record outputRec;
    outputRec.data = (void *) outputData;
    outputRec.length = reclen;

    //add to new file
    //RID insertRid;
    ifs = new InsertFileScan(result, status);
    status = ifs->insertRecord(outputRec, rid);
    if (status != OK){
      return status;
    }

  }//end while

  delete hfs;
  delete ifs;

  if (status != OK){
    return status;
  }

  return status; //should be OK by here

}
